#include "hx1838.h"

static int hx1838_probe(struct platform_device *pdev);
static int hx1838_remove(struct platform_device *pdev);

//hx1838资源
static struct hx1838_handle hx1838_handle[HX1838_NUMBER];

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id hx1838_of_match[] = {
	{.compatible = "atk,hx1838"},
	{ /* Sentinel */ }
};
//平台驱动
static struct platform_driver hx1838_drv = {
	.driver = {
		.name = "hx1838",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = hx1838_of_match,
	},
	.probe = hx1838_probe,
	.remove = hx1838_remove,
};

static int hx1838_parse(struct hx1838_handle *hx1838, uint8_t *data)
{
	int32_t i, j, k;

	memset(data, 0, 4);
	for(i=0,k=3; i<4; i++)
	{
		for(j=0; j<8; j++)
		{
			if(hx1838->edge_time[k+1]-hx1838->edge_time[k] > 600000)
				data[i] |= 0x01 << j;
			k += 2;
		}
	}
	//校验
	data[1] = ~data[1];
	data[3] = ~data[3];
	if((data[0] == data[1]) && (data[2] == data[3]))
		return 0;

	return -EINVAL;
}

static enum hrtimer_restart release_check(struct hrtimer *hrtimer)
{
	struct hx1838_handle *hx1838 = container_of(hrtimer, struct hx1838_handle, rep_timer);
	
	if(hx1838->current_key != 0xffffffff)
	{
		//上报按键松开事件
		input_report_key(hx1838->input, hx1838->current_key, 0);
		//上报完成
		input_sync(hx1838->input);
	}
	hx1838->current_key = 0xffffffff;

	//返回HRTIMER_NORESTART，表示不需要重启定时器
	return HRTIMER_NORESTART;
}

static enum hrtimer_restart timeout_handler(struct hrtimer *hrtimer)
{
	struct hx1838_handle *hx1838 = container_of(hrtimer, struct hx1838_handle, timeout_timer);

	memset(hx1838->edge_time, 0, sizeof(hx1838->edge_time));
	hx1838->edge_count = 0;

	//返回HRTIMER_NORESTART，表示不需要重启定时器
	return HRTIMER_NORESTART;
}

static irqreturn_t hx1838_handler(int irq, void *dev)
{
	int result;
	uint32_t id;
	uint64_t interval;
	uint8_t data[4];

	id = (uint32_t)dev;

	//设置中断超时处理定时器
	hrtimer_start(&hx1838_handle[id].timeout_timer, ktime_set(0, 50000000), HRTIMER_MODE_REL);

	//校验数据格式
	if(hx1838_handle[id].edge_count % 2 == 0)
	{
		//偶数个边沿应该是高电平
		if(gpio_get_value(hx1838_handle[id].gpio) != 0)
		{
			memset(hx1838_handle[id].edge_time, 0, sizeof(hx1838_handle[id].edge_time));
			hx1838_handle[id].edge_count = 0;
			return IRQ_HANDLED;
		}
	}
	else
	{
		//奇数个边沿应该是低电平
		if(gpio_get_value(hx1838_handle[id].gpio) != 1)
		{
			memset(hx1838_handle[id].edge_time, 0, sizeof(hx1838_handle[id].edge_time));
			hx1838_handle[id].edge_count = 0;
			return IRQ_HANDLED;
		}
	}

	//记录脉冲边沿触发时间
	hx1838_handle[id].edge_time[hx1838_handle[id].edge_count] = ktime_get_real_ns();
	//脉冲边沿计数
	hx1838_handle[id].edge_count++;

	//检查引导码是否错误
	if(hx1838_handle[id].edge_count == 3)
	{
		//正常引导码宽度4.5ms，重复引导码宽度2.25ms
		interval = hx1838_handle[id].edge_time[2] - hx1838_handle[id].edge_time[1];
		//小于1.75ms或大于5ms的均为错误格式
		if((interval < 1750000) || (interval > 5000000))
		{
			memset(hx1838_handle[id].edge_time, 0, sizeof(hx1838_handle[id].edge_time));
			hx1838_handle[id].edge_count = 0;
			return IRQ_HANDLED;
		}
	}

	//处理重复引导码
	if(hx1838_handle[id].edge_count == 4)
	{
		//正常引导码宽度4.5ms，重复引导码宽度2.25ms
		interval = hx1838_handle[id].edge_time[2] - hx1838_handle[id].edge_time[1];
		//在1.75ms~3ms之间的认为是重复码
		if((interval >= 1750000) && (interval < 3000000))
		{
			memset(hx1838_handle[id].edge_time, 0, sizeof(hx1838_handle[id].edge_time));
			hx1838_handle[id].edge_count = 0;

			//设置按键释放检测定时器
			hrtimer_start(&hx1838_handle[id].rep_timer, ktime_set(0, 150000000), HRTIMER_MODE_REL);
		}
	}

	//1bit引导码+8bit地址+8bit地址取反+8bit数据+8bit数据取反
	if(hx1838_handle[id].edge_count >= 68)
	{
		result = hx1838_parse(&hx1838_handle[id], data);
		if(result == 0)
		{
			//记录按键
			hx1838_handle[id].current_key = data[2];

			//上报按键按下事件
			input_report_key(hx1838_handle[id].input, hx1838_handle[id].current_key, 1);
			//上报完成
			input_sync(hx1838_handle[id].input);
		}

		memset(hx1838_handle[id].edge_time, 0, sizeof(hx1838_handle[id].edge_time));
		hx1838_handle[id].edge_count = 0;

		//设置按键释放检测定时器
		hrtimer_start(&hx1838_handle[id].rep_timer, ktime_set(0, 150000000), HRTIMER_MODE_REL);
	}

	//返回IRQ_HANDLED，表示中断被成功处理
	return IRQ_HANDLED;
}

//设备和驱动匹配成功执行
static int hx1838_probe(struct platform_device *pdev)
{
	int result;
	uint32_t id;
	uint32_t irq_flags;

	printk("%s\r\n", __FUNCTION__);

	//获取设备ID号
	result = of_property_read_u32(pdev->dev.of_node, "id", &id);
	if(result != 0)
	{
		printk("get dev id failed\r\n");
		return result;
	}
	if(id > HX1838_NUMBER)
	{
		printk("dev id invalid\r\n");
		return -EINVAL;
	}

	//检查是否占用
	if(hx1838_handle[id].use_flag) 
	{
		printk("dev id repetition\r\n");
		return -EINVAL;
	}
	pdev->id = id;

	//标记为已占用
	hx1838_handle[id].use_flag = 1;
	hx1838_handle[id].current_key = 0xffffffff;
	memset(hx1838_handle[id].edge_time, 0, sizeof(hx1838_handle[id].edge_time));
	hx1838_handle[id].edge_count = 0;

	//获取GPIO号
	hx1838_handle[id].gpio = of_get_named_gpio(pdev->dev.of_node, "data_pin", 0);
	if(hx1838_handle[id].gpio < 0)
	{
		hx1838_handle[id].use_flag = 0;
		printk("get gpio failed\r\n");
		return hx1838_handle[id].gpio;
	}
	//申请GPIO
	result = gpio_request(hx1838_handle[id].gpio, "hx1838");
	if(result < 0)
	{
		hx1838_handle[id].use_flag = 0;
		printk("request gpio failed\r\n");
		return result;
	}
	//设置GPIO为输入
	gpio_direction_input(hx1838_handle[id].gpio);

	//分配输入设备
	hx1838_handle[id].input = devm_input_allocate_device(&pdev->dev);
	if(!hx1838_handle[id].input)
	{
		gpio_free(hx1838_handle[id].gpio);
		printk("alloc input device failed");
		return -ENOMEM;
	}
	//设置输入设备名称
	hx1838_handle[id].input->name = "hx1838";
	//设置事件类型，按键事件
	__set_bit(EV_KEY, hx1838_handle[id].input->evbit);
	__set_bit(EV_REP, hx1838_handle[id].input->evbit);
	//设置事件码
	memset(hx1838_handle[id].input->keybit, 0xff, sizeof(hx1838_handle[id].input->keybit));
	//注册输入设备
	result = input_register_device(hx1838_handle[id].input);
	if(result)
	{
		gpio_free(hx1838_handle[id].gpio);
		hx1838_handle[id].use_flag = 0;
		printk("register input device failed");
		return result;
	}

	//初始化按键松开检测定时器
	hrtimer_init(&hx1838_handle[id].rep_timer, CLOCK_BOOTTIME, HRTIMER_MODE_REL);
	hx1838_handle[id].rep_timer.function = release_check;
	//初始化中断超时定时器
	hrtimer_init(&hx1838_handle[id].timeout_timer, CLOCK_BOOTTIME, HRTIMER_MODE_REL);
	hx1838_handle[id].timeout_timer.function = timeout_handler;

	//获取中断号
	hx1838_handle[id].irq = of_irq_get(pdev->dev.of_node, 0);
	if (hx1838_handle[id].irq <= 0)
	{
		hrtimer_cancel(&hx1838_handle[id].timeout_timer);
		hrtimer_cancel(&hx1838_handle[id].rep_timer);
		input_unregister_device(hx1838_handle[id].input);
		gpio_free(hx1838_handle[id].gpio);
		hx1838_handle[id].use_flag = 0;
		printk("irq get failed");
		return hx1838_handle[id].irq;
	}
	//获取中断触发方式
	irq_flags = irq_get_trigger_type(hx1838_handle[id].irq);
	if(irq_flags != (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING))
	{
		hrtimer_cancel(&hx1838_handle[id].timeout_timer);
		hrtimer_cancel(&hx1838_handle[id].rep_timer);
		input_unregister_device(hx1838_handle[id].input);
		gpio_free(hx1838_handle[id].gpio);
		hx1838_handle[id].use_flag = 0;
		printk("get irq trigger failed");
		return -EINVAL;;
	}
	//注册中断处理函数
	result = request_irq(hx1838_handle[id].irq, hx1838_handler, irq_flags, "hx1838_irq", (void*)id);
	if(result < 0)
	{
		hrtimer_cancel(&hx1838_handle[id].timeout_timer);
		hrtimer_cancel(&hx1838_handle[id].rep_timer);
		input_unregister_device(hx1838_handle[id].input);
		gpio_free(hx1838_handle[id].gpio);
		hx1838_handle[id].use_flag = 0;
		printk("irq request failed");
		return result;
	}

	return 0;
}

//设备或驱动卸载时执行
static int hx1838_remove(struct platform_device *pdev)
{
	uint32_t id;

	printk("%s\r\n", __FUNCTION__);

	id = pdev->id;
	if(!hx1838_handle[id].use_flag)
	{
		printk("verification failed\r\n");
		return -EINVAL;
	}

	//释放中断处理函数
	free_irq(hx1838_handle[id].irq, (void*)id);;
	//删除定时器
	hrtimer_cancel(&hx1838_handle[id].timeout_timer);
	hrtimer_cancel(&hx1838_handle[id].rep_timer);
	//注销输入设备
	input_unregister_device(hx1838_handle[id].input);
	//释放GPIO
	gpio_free(hx1838_handle[id].gpio);

	hx1838_handle[id].use_flag = 0;

	return 0;
}

static int __init hx1838_drv_init(void)
{
	int i;
	int err = 0;

	printk("%s\r\n", __FUNCTION__);

	for(i=0; i<HX1838_NUMBER; i++)
	{
		hx1838_handle[i].use_flag = 0;
		hx1838_handle[i].current_key = 0xffffffff;
		memset(hx1838_handle[i].edge_time, 0, sizeof(hx1838_handle[i].edge_time));
		hx1838_handle[i].edge_count = 0;
	}

	//注册平台驱动
	err = platform_driver_register(&hx1838_drv);
	if(err != 0)
	{
		printk("add cdev failed\r\n");
		return err;
	}
	return err;
}

static void __exit hx1838_drv_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销平台驱动
	platform_driver_unregister(&hx1838_drv);
}

module_init(hx1838_drv_init);
module_exit(hx1838_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("hx1838_drv");
